package channel;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.util.Iterator;
import java.util.Properties;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.DefaultHttpClientConnection;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestExecutor;
import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestExpectContinue;
import org.apache.http.protocol.RequestTargetHost;
import org.apache.http.protocol.RequestUserAgent;

   public class comChannel 
   {
	   
	   //private static Logger log = LoggerFactory.getLogger(CommChannel.class.getName());
	   public static final int DEFAULT_TIME_OUT = 3000;
	   public static final String COMM_HTTP = "http";
	   public static final String COMM_HTTPS = "https";
	   
	   private String host = null;
	   private String restType = COMM_HTTP;
	   private int port = 0;
	   private boolean isSecure = false;
	   public comChannel(String host, int port, boolean isSecure) throws Exception 
	   {
		   this.host = host;
		   this.port = port;
		   this.isSecure = isSecure;
		   
		   if(this.isSecure ) 
		   {
			   restType = COMM_HTTPS;
		   } 
		   else if(this.isSecure == false && port == 443)  
		   {
			   restType = COMM_HTTPS;
		   }
	   }
	   	
	   public UCSResponse getUCSConection( Properties props,byte[] buff) throws Exception 
	   {
	   		
	   		BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST","/nuova");
	   		HttpEntity[] requestBodies = { new InputStreamEntity(new ByteArrayInputStream(buff),buff.length ) };
	   		request.setEntity(requestBodies[0]);
         
	   	 	HttpParams params = new BasicHttpParams();
		    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
		    HttpProtocolParams.setContentCharset(params, "UTF-8");
		    HttpProtocolParams.setUserAgent(params, "HttpComponents/1.1");
		    HttpProtocolParams.setUseExpectContinue(params, true);
		     	     
		    // Required protocol interceptors
		    BasicHttpProcessor httpproc = new BasicHttpProcessor();
		    httpproc.addInterceptor(new RequestContent());
		    httpproc.addInterceptor(new RequestTargetHost());
		    UCSResponse res=new UCSResponse();
		    
		    // Recommended protocol interceptors
		    httpproc.addInterceptor(new RequestConnControl());
		    httpproc.addInterceptor(new RequestUserAgent());
		    httpproc.addInterceptor(new RequestExpectContinue());
		    HttpResponse response=null;
		    SSLContext sslcontext = null;
		    try 
		    {
		     	if(this.restType.equals("https")) 
		     	{
		     		
		     		TrustManager[] trustAllCerts = new TrustManager[]{
		     				  new X509TrustManager() {
		                      public java.security.cert.X509Certificate[] getAcceptedIssuers() {return null;}
		                      public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType){}
		                      public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType){}
		                  }
		              };
		     	 sslcontext = SSLContext.getInstance("SSL");
		     	 sslcontext.init(null, trustAllCerts, new java.security.SecureRandom());
		      
		    	 }
		    } 
		    catch(Exception e) 
		    {
		           throw new IOException(e);
		    }
		    
		    HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
		    HttpContext context = new BasicHttpContext(null);
		    DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
		    HttpHost host = new HttpHost(this.host,this.port);
		    
		    context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
		    context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, host);
		    //ConnectionReuseStrategy connStrategy = new DefaultConnectionReuseStrategy();
		    
		    Socket socket=null;
		    try
		    {
		       
		    		SocketAddress socketAddress = new InetSocketAddress(InetAddress.getByName(this.host), this.port); 
		    		if(this.restType.equals("https")) 
			     	{
		    			socket = sslcontext.getSocketFactory().createSocket();
			     	}
		              
		    		else
		    		{
		    				socket=new Socket();
		    		}
		            socket.connect(socketAddress, DEFAULT_TIME_OUT);	 
		  } 
		   catch(SocketTimeoutException e)
		   {
		    	throw e;
		   }
		   catch (Exception e) 
		   {
		    	//ignore
		   }
		   try
		   {
		    	
			   if (!conn.isOpen()) 
			   {
		    	    conn.bind(socket, params);
			   }

			   // Set the Parameters
			   if(props != null) 
			   {
		    	    @SuppressWarnings("rawtypes")
		    	    Iterator itr = props.keySet().iterator();
		    	    while(itr.hasNext()) 
		    	    {
		    	    	String keyi = (String)itr.next();
		    	    	Object val  = props.get(keyi);
		    	    	params.setParameter(keyi, val);
		    	    }
			   }
		    	   
			   request.setParams(params);
			   httpexecutor.preProcess(request, httpproc, context);
			   response = httpexecutor.execute(request, conn, context);
			   httpexecutor.postProcess(response, httpproc, context);
		    	            
			   //Modifying this to set the device states response as a header temporarily
			   long contentLen = response.getEntity().getContentLength();
		    	            
			   Header encType = response.getLastHeader("Transfer-Encoding");
		    	            
			   System.out.println("UCS[" + host + "]: Response: Code" + response.getStatusLine().getStatusCode()
		    	              + ", CL: " + contentLen + ", Enc Type:" + encType);
		    	            
			   if(encType != null && encType.getValue().equalsIgnoreCase("chunked")) 
			   {
		    	         
				   StringBuffer buff2 = new StringBuffer();
		    	   BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
		    	   String line = null;
		    	   do
		    	   {
		    	         line = br.readLine();
		    	         if(line != null)
		    	           buff2.append(line);
		    	   } while(line != null);
		    	   res.setBuff(buff2.toString());
			   } 
			   else if(contentLen > 0) 
			   {
				   res.setContentLen((int)contentLen);
				   DataInputStream in = null;
		    	   try 
		    	   {
		    	         in = new DataInputStream(response.getEntity().getContent());
		    	         byte[] buffer = new byte[(int)contentLen];
		    	         in.readFully(buffer);
		    	         res.setBuff(new String(buffer));
		    	   } 
		    	   catch (Exception e) 
		    	   {
		    	          //ignore
		    	   }
		    	   finally 
		    	   {
		    	        try 
		    	        {
		    	            in.close();
		    	        } 
		    	        catch (Exception e) 
		    	        {
		    	               //ignore
		    	        }
		    	    }
		    }
		    	            
		}
		catch(SocketTimeoutException e)
		{
			throw e;
		}
		catch (Exception e) 
		{
			
			throw new IOException(e);
		}
		finally 
		{
			try 
			{
				conn.close();
			} 
			catch (Exception e) 
			{
		    	    //ignore
		    }
		}
		
		   return res; 

	}
	public UCSResponse getCommChannel(String buff) throws Exception
	{
		try
		{
	   		return getUCSConection(null,buff.getBytes());
	   	}
	   	catch(Exception e)
	   	{
	   			throw e;
	   	}
	}
}


